#include "../utils/pch.h"
#include "../utils/IniReader.h"
#include "../utils/PcapUtils.h"
#include "../utils/FileUtils.h"
#include "main.h"
#include "../utils/SafeQueueTemplate.h"
#include "../utils/SPMCQueueTemplate.h"
#include "../utils/SocketUtils.h"
//#include "../utils/Socket.h"

// 版本控制宏
#ifdef MY_COMPILE_TIME
extern const char* my_compile_time = MY_COMPILE_TIME;
extern const char* my_version = MY_VERSION;
#else
const char* my_compile_time = "Unknown";
const char* my_version = "Unknown";
#endif

// 全局共享配置
namespace Global {
    const std::string Version = "0.0.2";
    const std::string Date = "0.0.2";

    // 声明全局变量
    std::string globalString = ""; // 定义，声明在pch.h中
    int globalInt = 0;
    int g_exit = 0; // 退出标志
}

namespace ntp{
    // 定义全局变量
    std::string global_message = "Hello, World!";
    std::mutex global_mutex;

    // 共享的日志对象
    std::shared_ptr<spdlog::logger> my_nm_logger;



    // 共享队列1 = 普通队列
    std::queue<MarketData> data_queue1;
    std::queue<MarketData> data_queue2;
    SafeQueue<MarketData> queueLine1, queueLine2;
    constexpr uint32_t QUEUE_SIZE = 16; // 队列大小必须是2的幂次
    SPMCQueue<MarketData, 1024> queueL1, queueL2;



}

#define HOME_DIR "/tmp/tmp.FdUHWCPhyb/V2"

std::shared_ptr<spdlog::logger> spdlog_init() {
    // 初始化异步线程池
    spdlog::init_thread_pool(8192, 1);
    // 创建 sinks
    auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
    console_sink->set_level(spdlog::level::debug);

    auto file_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(
            "logs/app.log", 1024 * 1024 * 5, 3);
    file_sink->set_level(spdlog::level::info);

    // 创建异步日志器
    auto logger = std::make_shared<spdlog::async_logger>(
            "async_logger", spdlog::sinks_init_list{console_sink, file_sink},
            spdlog::thread_pool(), spdlog::async_overflow_policy::block);
    logger->set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] [%s:%#] %v");
    spdlog::register_logger(logger);

    return logger;
}

// 将指定的线程绑定到特定的 cpu 核心上
bool bind_cpu(int cpu_id, pthread_t thd_id) {
    int cpu = (int)sysconf(_SC_NPROCESSORS_ONLN);
    cpu_set_t cpu_info;

    if (cpu < cpu_id) {
        return false;
    }

    CPU_ZERO(&cpu_info); // 使用 CPU_ZERO 函数清空 cpu_info 集合，确保其初始状态为空
    CPU_SET(cpu_id, &cpu_info); // 使用 CPU_SET 函数将指定的 cpu_id 添加到 cpu_info 集合中

    if (pthread_setaffinity_np(thd_id, sizeof(cpu_set_t), &cpu_info) != 0) {
        return false;
    }

    return true;
}

// 信号处理函数
extern "C" void my_signalHandler(int signal) {
    // 停止时开始统计
    std::cout << "停止信号处理函数" << std::endl;
    // 刷新缓冲区并正常退出程序
    exit(0);
}

static void sigIntHander(int signalNum) {
    ntp::my_nm_logger->info("捕获到停止信号 {}", signalNum);
    Global::g_exit = 1;
}

void SignalProcess() {
    // 捕获到退出信号后，修改退出标记，执行退出动作
    signal(SIGINT, sigIntHander);
    signal(SIGKILL, sigIntHander);
    signal(SIGTERM, sigIntHander);
}

void exitFunction() {
    // 执行统计计算逻辑
    std::cout << "退出函数回调." << std::endl;
    //ntp::FileUtils fu;
    //fu.ReadFileAndStatistics();
}

int main(int argc, char *argv[]) {
    std::string debug;
    if (argc > 1) {
        debug = argv[1]; // 默认没有debug, 加debug参数后有debug功能
    }
    using namespace ntp;
    // 将信号处理函数注册为处理 SIGINT 信号
    std::signal(SIGINT, my_signalHandler);
    //std::atexit(exitFunction); // 使用std::atexit注册函数，需要一个不带参数且返回类型为void类型地函数指针
    //SignalProcess(); // 可能有问题，无法停止，原因未知

    // 初始化运行时日志
    //ntp::my_nm_logger = spdlog::basic_logger_mt("test_logger", "runingTimeLogger.txt"); // basic_logger 固定写法
    //spdlog::set_default_logger(my_nm_logger);
    //spdlog::flush_on(spdlog::level::info);
    //spdlog::get("test_logger")->info("LoggingTest::ctor");

    ntp::my_nm_logger = spdlog_init();
    // 使用日志器
    SPDLOG_LOGGER_INFO(my_nm_logger,"============================ 程序开始执行 ============================");
    SPDLOG_LOGGER_INFO(my_nm_logger,"程序基本信息: version: {}, my_compile_time: {}, spdlog: {}", my_version, my_compile_time, my_nm_logger->name());


    // 获取启动时间
    auto aa = currTime();
    // 获取当前时间作为启动时间
    std::chrono::system_clock::time_point startTime = std::chrono::system_clock::now();
    // 获取当前工作路径
    char cwd[1024];
    if (getcwd(cwd, sizeof(cwd)) == NULL) {
        perror("getcwd");
        return 1;
    }


    // 初始化配置文件对象
    IniReader* iniCfg = new IniReader();
    std::string cwdStr(cwd);
    std::string cfgPathName = cwdStr + "/my_config.ini";
    //std::string cfgPathName = HOME_DIR"/my_config.ini";

    SPDLOG_LOGGER_INFO(my_nm_logger, "程序启动路径为：{} ,启动时间：{}", cwd, aa);
    SPDLOG_LOGGER_INFO(my_nm_logger, "读取的配置文件：{}", cfgPathName);

    if (!iniCfg->ReadConfig(cfgPathName)) {
        SPDLOG_LOGGER_INFO(my_nm_logger, "读取 ini 配置文件失败");
        exit;
    }
    else {
        SPDLOG_LOGGER_INFO(my_nm_logger, "读取 my_config.ini 配置文件成功");
    }

    // 获取配置文件中的cpu集合
    std::string cpu_set = iniCfg->ReadString("MODE", "cpuset", "0,1,2,3,4,5,6,7");
    std::vector<std::string> cpu_set_vec = splitByDelimiter(cpu_set, ',');

    // 抓包模式
    std::string packetMode = iniCfg->ReadString("MODE", "packetMode", "0");

    // 初始化公共数据类
    ShareDataClzz* shareDataClzz = new ShareDataClzz(iniCfg);


    // pcap库
    PcapUtils pcapUtils(my_nm_logger, shareDataClzz);
    SocketUtils socketUtils(my_nm_logger);
    //socketUtils.readNetworkIfaceLine("LINE_1", startTime, iniCfg, &queueLine1, debug);

/*    {
        using UdpReceiver = SocketUdpReceiver<>;
        UdpReceiver receiver;
        if (!receiver.init("interface", "local_ip", 12345, "sub_ip")) {
            std::cout << receiver.getLastError() << std::endl;
            //return 1;
        }

        int cur = 0;
        int bad_cnt = 0;
        int miss_cnt = 0;
        int cnt = 0;
        while (1) {
            receiver.read([&](const uint8_t* data, uint32_t len, timespec ts) {
                cnt++;
                std::cout << "原始数据包: ts.tv_sec=" << ts.tv_sec << ":" << ts.tv_nsec << std::endl;
                // 输出原始数据包内容，以十六进制形式输出
                for (int i = 0; i < 20; i++) {
                    printf("%02x ", data[i]);
                    if ((i + 1) % 20 == 0) {
                        printf("\n");
                    }
                }
                printf("\n");

                if (len != 201) {
                    std::cout << "error len: " << len << std::endl;
                    bad_cnt++;
                    return;
                }
                while (data[0] != cur + '0') {
                    miss_cnt++;
                    std::cout << "miss: " << (char)(cur + '0') << std::endl;
                    cur++;
                    if (cur == 10) cur = 0;
                }
                for (int i = 0; i < 200; i++) {
                    if (data[i] != data[0]) {
                        std::cout << "invalid data: " << data << std::endl;
                        bad_cnt++;
                        break;
                    }
                }
                cur++;
                if (cur == 10) cur = 0;
            });
        }

    }*/


    // 获取线程id
    //std::thread::id threadId = std::this_thread::get_id();
    //std::cout << "===" << threadId << std::endl;

    // 读取两路行情，用同一个起点做对比
    auto readLambda = [](PcapUtils pcapUtils, std::shared_ptr<spdlog::logger> my_logger,
            IniReader* iniCfg, std::chrono::system_clock::time_point startTime, SafeQueue<MarketData>* data_queue1, SafeQueue<MarketData>* data_queue2,
                         std::string debug) {
        // 获取线程id
        std::thread::id threadId = std::this_thread::get_id();
        std::cout << "===" << threadId << std::endl;
        SPDLOG_LOGGER_INFO(my_logger,"消费者线程 - 启动读行情线程-{}",2);
        pcapUtils.readMsg(my_logger, iniCfg, data_queue1, data_queue2, debug);
    };
    //std::thread task2(readLambda, pcapUtils, my_nm_logger, iniCfg, startTime, &queueLine1, &queueLine2, debug);
    //pcapUtils.readMsg(my_nm_logger, iniCfg, &queueLine1, &queueLine2);

    // 写行情1
    auto writeLambda1 = [](ntp::PcapUtils pcapUtils, ntp::SocketUtils socketUtils,
            std::shared_ptr<spdlog::logger> my_logger, IniReader* iniCfg,
            std::chrono::system_clock::time_point startTime, SafeQueue<MarketData>* data_queue,
                           std::string debug, std::string packetMode) {
        SPDLOG_LOGGER_INFO(my_logger,"生产者线程1 - 启动写行情线程1");
        if (packetMode == "0") {
            pcapUtils.readNetworkIfaceLine("LINE_1", startTime, iniCfg, data_queue, debug);
        } else if (packetMode == "1") {
            //socketUtils.readNetworkIfaceLine("LINE_1", startTime, iniCfg, data_queue, debug);
            socketUtils.readNetworkIfaceLine_epoll("LINE_1", startTime, iniCfg, data_queue, debug);
        }
    };
    std::thread task(writeLambda1, pcapUtils, socketUtils, my_nm_logger, iniCfg, startTime, &queueLine1, debug, packetMode);
    if (bind_cpu(std::stoi(cpu_set_vec[0]), task.native_handle())) {
        SPDLOG_LOGGER_INFO(my_nm_logger, "线程:{} 绑定的cpu核心:{}", task.native_handle(), cpu_set_vec[0]);
    } else {
        SPDLOG_LOGGER_ERROR(my_nm_logger, "线程:{} 绑定cpu核心失败", task.native_handle());
        exit;
    }

    // 写行情2
    auto writeLambda2 = [](PcapUtils pcapUtils, ntp::SocketUtils socketUtils,
            std::shared_ptr<spdlog::logger> my_logger, IniReader* iniCfg,
            std::chrono::system_clock::time_point startTime, SafeQueue<MarketData>* data_queue,
                           std::string debug, std::string packetMode) {
        SPDLOG_LOGGER_INFO(my_logger,"生产者线程2 - 启动写行情线程2");
        if (packetMode == "0") {
            pcapUtils.readNetworkIfaceLine("LINE_2", startTime, iniCfg, data_queue, debug);
        } else if (packetMode == "1") {
            //socketUtils.readNetworkIfaceLine("LINE_2", startTime, iniCfg, data_queue, debug);
            socketUtils.readNetworkIfaceLine_epoll("LINE_2", startTime, iniCfg, data_queue, debug);
        }
    };
    std::thread task3(writeLambda2, pcapUtils, socketUtils, my_nm_logger, iniCfg, startTime, &queueLine2, debug, packetMode);
    if (bind_cpu(std::stoi(cpu_set_vec[1]), task3.native_handle())) {
        SPDLOG_LOGGER_INFO(my_nm_logger, "线程:{} 绑定的cpu核心:{}", task3.native_handle(), cpu_set_vec[1]);
    } else {
        SPDLOG_LOGGER_ERROR(my_nm_logger, "线程:{} 绑定cpu核心失败", task3.native_handle());
        exit;
    }


    // 采样统计
    auto sampledLambda = [](PcapUtils pcapUtils, std::shared_ptr<spdlog::logger> my_logger, IniReader* iniCfg, std::chrono::system_clock::time_point startTime) {
        my_logger->info("采样统计线程 - 启动读行情线程");
        pcapUtils.saveFile(my_logger, iniCfg);
    };
    //std::thread task4(sampledLambda, pcapUtils, my_nm_logger, iniCfg, startTime);

    // 等待线程结束
    //task2.join();
    task.join();
    task3.join();
    //task4.join();

    SPDLOG_LOGGER_INFO(my_nm_logger,"程序结束 g_exit= {}",Global::g_exit);

    // ======================================================================= 多路/若干路行情对比
/*    // 循环创建多个线程，采集，写文件
    unsigned int n = std::thread::hardware_concurrency();
    std::cout << "硬件并发数: " << n << std::endl;
    std::vector<std::string> lineNames = iniCfg->GetSimilarConfigNames("LINE");
    auto threadWork = [](ntp::PcapUtils pcapUtils, std::shared_ptr<spdlog::logger> my_logger,
                           IniReader* iniCfg, std::chrono::system_clock::time_point startTime, std::string lineName) {
        SPDLOG_LOGGER_INFO(my_logger,"生产者线程1 - 启动写行情线程1");
        pcapUtils.readNetwork(lineName, startTime, iniCfg);
    };
    std::vector<std::thread> threads;
    for (int i = 0; i < 1*//*lineNames.size()*//*; i++) {
        std::thread task4(threadWork, pcapUtils, my_nm_logger, iniCfg, startTime, lineNames[i]);
        threads.push_back(std::move(task4));
    }
    // 线程数量
    std::cout << "线程数量: " << threads.size() << std::endl;
    for (auto& thread : threads) {
        thread.join();
    }*/



}
